import { CardRank, CardSuit, MapCardConfig, MapConfig } from '../GameDef';
import { CardInPool, CardInMountain } from '../models/Card';
import { GenerateMapRule } from '../rules/GenerateMapRule';
import Tools from '../tools/tools';

/**
 * 牌库类 - 管理一组卡牌 (单例模式)
 */
export class CardPoolMgr {
    /** 单例实例 */
    private static _instance: CardPoolMgr | null = null;

    /** 牌库ID */
    private _uid: string;

    /**
     * 获取牌库ID
     */
    get uid(): string {
        return this._uid;
    }

    /**
     * 私有构造函数
     * @param uid 牌库ID
     * @param name 牌库名称
     * @param cards 初始卡牌列表
     */
    private constructor() {
        this._uid = '';
        this._cards = [];
    }

    /** 牌库中的卡牌 */
    private _cards: CardInPool[] = [];

    /**
     * 获取牌库中的所有卡牌
     */
    get cards(): CardInPool[] {
        return [...this._cards];
    }

    /**
     * 获取牌库中卡牌数量
     */
    get size(): number {
        return this._cards.length;
    }

    /**
     * 检查牌库是否为空
     */
    get isEmpty(): boolean {
        return this._cards.length === 0;
    }

    /**
     * 获取牌库单例实例
     * @param name 牌库名称 (仅首次调用时有效)
     * @param cards 初始卡牌列表 (仅首次调用时有效)
     * @returns 牌库单例实例
     */
    public static getInstance(): CardPoolMgr {
        if (!CardPoolMgr._instance) {
            CardPoolMgr._instance = new CardPoolMgr();
        }
        return CardPoolMgr._instance;
    }

    /**
     * 重置单例实例
     * 在需要完全重新初始化牌库时使用
     */
    public static resetInstance(): void {
        CardPoolMgr._instance = null;
    }

    /**
     * 添加卡牌到牌库
     * @param card 要添加的卡牌
     */
    addCard(card: CardInPool): void {
        this._cards.push(card);
    }

    /**
     * 批量添加卡牌到牌库
     * @param cards 要添加的卡牌列表
     */
    addCards(cards: CardInPool[]): void {
        this._cards.push(...cards);
    }

    /**
     * 从牌库中移除卡牌
     * @param card 要移除的卡牌
     * @returns 是否成功移除
     */
    removeCard(card: CardInPool): boolean {
        const index = this._cards.findIndex(c => c.uid === card.uid);
        if (index !== -1) {
            this._cards.splice(index, 1);
            return true;
        }
        return false;
    }

    /**
     * 根据条件从牌库中获取卡牌
     * @param condition 筛选条件
     * @returns 符合条件的卡牌列表
     */
    getCardsByCondition(condition: (card: CardInPool) => boolean): CardInPool[] {
        return this._cards.filter(condition);
    }

    /**
     * 根据ID获取卡牌
     * @param uid 卡牌ID
     * @returns 找到的卡牌，如果不存在则返回undefined
     */
    getCardById(uid: number): CardInPool | undefined {
        return this._cards.find(card => card.uid === uid);
    }

    /**
     * 根据花色和点数获取卡牌
     * @param suit 花色
     * @param rank 点数
     * @returns 找到的卡牌，如果不存在则返回undefined
     */
    getCardBySuitAndRank(suit: CardSuit, rank: CardRank): CardInPool | undefined {
        return this._cards.find(card => card.suit === suit && card.rank === rank);
    }

    getCardByValue(cardid: number): CardInPool | undefined {
        return this._cards.find(card => card.isUsed == false && card.cardId === cardid);
    }

    /**
     * 随机获取一张卡牌
     * @param condition 可选的筛选条件
     * @returns 随机卡牌，如果牌库为空则返回undefined
     */
    getRandomCard(condition?: (card: CardInPool) => boolean): CardInPool | undefined {
        const availableCards = condition ? this._cards.filter(condition) : this._cards;
        if (availableCards.length === 0) {
            return undefined;
        }
        const randomIndex = Math.floor(Math.random() * availableCards.length);
        return availableCards[randomIndex];
    }

    getUnusedCard(): CardInPool | undefined {
        // 从牌库中随机获取一张未使用的卡牌
        return this.getRandomCard(card => !card.isUsed);
    }

    getUnusedCards(): CardInPool[] {
        let ret = [];
        this._cards.forEach(card => {
            if (!card.isUsed)
                ret.push(card);
        });
        return ret;
    }

    /**
     * 洗牌 - 随机打乱牌库中的卡牌顺序
     */
    shuffle(): void {
        // Fisher-Yates 洗牌算法
        for (let i = this._cards.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [this._cards[i], this._cards[j]] = [this._cards[j], this._cards[i]];
        }
    }

    /**
     * 重置牌库中所有卡牌的状态
     */
    reset(): void {
        this._cards.forEach(card => card.reset());
    }

    /**
     * 清空牌库中的所有卡牌
     */
    clear(): void {
        this._cards = [];
    }

    /**
     * 加载新的卡牌集合到牌库中
     * 用于在切换关卡时更换新的牌库
     * @param cards 要加载的卡牌列表
     */
    async load(filename: string): Promise<void> {
        // 清空当前牌库
        this.clear();

        let poolConfig = await Tools.loadJson(`maps/${filename}`);

        if (!poolConfig)
            return console.log("loadCards failed! poolConfig is null!");

        this._uid = filename;
        for (let i = 0; i < poolConfig.length; i++) {
            let card = poolConfig[i];
            let c = new CardInPool(card.uid, card.value, card.orderid);
            this.addCard(c);
        }
    }

    fixWrongCard(uid: number, value: number, orderId: number): number {
        let ret = -1;
        let card = this.getCardById(uid);
        if (card) {
            ret = card.fixWrongCard(value, orderId);
        }
        return ret;
    }

    async generateMap(filename: string): Promise<CardInMountain[][]> {
        let mapConfig: MapConfig = await Tools.loadJson(`maps/${filename}`);

        if (!mapConfig) {
            console.log('loadCards failed! mapConfig is null!');
            return [];
        }

        let rules = new GenerateMapRule();
        const generateCard = function (mapCardCfg: MapCardConfig, pool:CardPoolMgr): CardInMountain {
            if (mapCardCfg) {
                let params = [];
                let fname = mapCardCfg.ruleid;
                if (mapCardCfg.iscustom == false) {
                    fname = 'fix'
                } else {
                    let agList = mapCardCfg.ruleid.split('_');
                    if (agList.length > 1) {
                        fname = agList[0];
                        params = agList.slice(1)
                    }
                }

                let genfunc = rules[fname];
                if (!genfunc) {
                    console.log(`generate rule [${mapCardCfg.ruleid}] is null!`);
                }

                let card = genfunc.call(rules, CardPoolMgr.getInstance(), mapCardCfg, params);
                if (!card) {
                    console.log(`generate card [${JSON.stringify(mapCardCfg)}] failed!`);
                    card = pool.getUnusedCard();
                }
                card.markAsUsed();

                // 组装需要的数据
                return new CardInMountain(card, mapCardCfg);
            }
        };

        let cuids: number[][] = mapConfig.cuids;
        let result: CardInMountain[][] = new Array(cuids.length);

        // 为每个地图卡片分配实际的卡牌, 优先生成固定的卡牌
        for (let i = cuids.length - 1; i >= 0; --i) {
            let rlist: CardInMountain[] = new Array(cuids[i].length);
            for (let j = 0; j < cuids[i].length; j++) {
                let mapCardCfg = mapConfig.cards[cuids[i][j]];
                if (mapCardCfg && mapCardCfg.iscustom == false) {
                    let cm = generateCard(mapCardCfg, this);
                    rlist[j] = cm;
                }
            }
            result[i] = rlist;
        }

        // 随机生成剩余的卡牌
        for (let i = cuids.length - 1; i >= 0; --i) {
            for (let j = 0; j < cuids[i].length; j++) {
                let mapCardCfg = mapConfig.cards[cuids[i][j]];
                if (mapCardCfg && mapCardCfg.iscustom) {
                    let cm = generateCard(mapCardCfg, this);
                    result[i][j] = cm;
                }
            }
        }

        return result;
    }
}